Front Matter

# clean up workspace environment
rm(list = ls())
# all packages used for the assignment
library(mosaicData)
library(DataComputing)
library(dplyr)
library(tidyverse)
library(ggplot2)
library(lubridate)

Guiding Question: Is there any correlation between number of likes, dislikes and comments on YouTube Videos? (Can we find any relationship between number of views, likes, dislikes and comments from YouTube videos?)

  1. We want to find whether there is any relationship bebtween number of views, likes, dislikes and comments from YouTube videos?
  2. We want to know recent trend of YouTube viewers and their activity through data of views, likes, dislikes and comments
  3. The data has time frame starting from Nov 2017 ending in June 2018.

Import data

file_location <- file.choose()

us_youtube_trend <- read.csv(file_location) %>%
                        mutate(country = "US")

file_location <- file.choose()

ca_youtube_trend <- read.csv(file_location) %>%
                        mutate(country = "CA")

youtube_trend <- rbind(us_youtube_trend, ca_youtube_trend)

Getting data from “USvideos.csv” and “CAvideos.csv” which is given by Mitchell J in Kaggle. The kaggle link is following: https://www.kaggle.com/datasnaek/youtube-new\. The data was originally collected for data sharing in Kaggle webpage about 2 years ago. Each case represent one trending YouTube video. For example, there is a row about YouTube video posted by Eminem. It was treding on Nov 14, 2017 and had views of 17158579, likes of 787425, dislikes of 43420, and comments of 125882. In our dataset, there are 40926 rows of trending YouTube videos. I plan to use variables “trending_date”, “views”, “likes”, “dislikes”, “comment_count”, and “comment_disabled”. The region is US AND Canada.

Inspect data

The six example rows are shown below

head(youtube_trend)

These are the column names of “youtube_trend” data frame

names(youtube_trend)
 [1] "video_id"              
 [2] "trending_date"         
 [3] "title"                 
 [4] "channel_title"         
 [5] "category_id"           
 [6] "publish_time"          
 [7] "tags"                  
 [8] "views"                 
 [9] "likes"                 
[10] "dislikes"              
[11] "comment_count"         
[12] "thumbnail_link"        
[13] "comments_disabled"     
[14] "ratings_disabled"      
[15] "video_error_or_removed"
[16] "description"           
[17] "country"               

Clean data

youtube_trend <- youtube_trend %>%
                    filter(video_error_or_removed == "False") %>%
                    mutate(trending_date = ydm(trending_date))

Remove videos that were removed or was confirmed to be an error. These videos are classified as “True” for column “video_error_or_removed”

Relationship between number of views, likes, dislikes, and comments in a single video

ggplot(youtube_trend, aes(x = views, y = likes, color = country)) + geom_point()

We can see from the scatterplot that there seems to be a logarithmic relationship between number of views and number of likes in a YouTube video.

ggplot(youtube_trend, aes(x = views, y = dislikes, color = country)) + geom_point()

We can see from the scatterplot that there seems to be a linear relationship between number of views and number of dislikes in YouTube videos. This means that it is evitable that there should be increase in dislikes when number of views increase. We can aslo see some videos have higer rate of increasing dislikes for certain amount of views.

ggplot(youtube_trend, aes(x = views, y = comment_count, color = country)) + geom_point()

We can see from the scatterplot that there seems to be a logarithmic (but very close to linear) relationship between number of views and number of comments in YouTube videos.

ggplot(youtube_trend, aes(x = likes, y = dislikes, color = country)) + geom_point()

We can see from the scatterplot that there seems to be a very straight linear relationship between number of likes and number of dislikes in YouTube videos.

ggplot(youtube_trend, aes(x = likes, y = comment_count, color = country)) + geom_point()

We can see from the scatterplot that there seems to be a very straight linear relationship between number of likes and number of cimments in YouTube videos.

ggplot(youtube_trend, aes(x = dislikes, y = comment_count, color = country)) + geom_point()

We can see from the scatterplot that there seems to be a logarithmic relationship between number of dislikes and number of comment in YouTube videos.

Is there any relationship between disabling comment and number of dislikes a YouTube video received?

com_dis <- youtube_trend %>%
              filter(comments_disabled == "True")

mean(com_dis$dislikes)
[1] 1960.685
mean(com_dis$likes)
[1] 17946.33
com_non_dis <- youtube_trend %>%
                  filter(comments_disabled == "False")

mean(com_non_dis$dislikes)
[1] 2875.127
mean(com_non_dis$likes)
[1] 57532.42

The YouTube videos with comment disabled have average number of 1960.685 dislikes and average number of 17946.33 likes. YouTube videos with comment not disabled has average number of 2875.127 dislikes and average number of 57532.42 likes. We can see that videos that have comment disabled got much less likes and dislikes than vidoes that have comment enabled.

For YouTube videos with more dislikes than likes, do these videos have higer probability of disabling comments than videos that have more likes than dislikes?

more_dislike <- youtube_trend %>%
                  filter(dislikes > likes)
more_like <- youtube_trend %>%
                filter(likes > dislikes) %>%
                sample_n(841)

As there are only 841 videos that have more dislikes than likes, we will also sample only 841 videos from list of videos that have more likes than dislikes.

com_dis_df <- data.frame(Date=as.Date(character()),
                 File=character(), 
                 User=character(), 
                 stringsAsFactors=FALSE) 

nrow(more_dislike)
[1] 841
com_dis_dis <- sum(more_dislike$comments_disabled == "True")
com_dis_dis
[1] 53
nrow(more_like)
[1] 841
com_dis_non <- sum(more_like$comments_disabled == "True")
com_dis_non
[1] 11

From 841 YouTube videos that have more dislikes than likes, there are 53 videos that have their comments disabled. From 841 YouTube videos that have more likes than dislikes, there are 13 videos that have their comments disabled. (**The number of videos that have more likes than dislikes while comments are disabled might vary as the sample might change from sampling)

com_dis_df <- rbind(com_dis_df, c("more like", com_dis_non/nrow(more_like)), c("more dislike", com_dis_dis/nrow(more_dislike))) 

colnames(com_dis_df) <- c("category", "proportion")

com_dis_df
ggplot(com_dis_df, aes(x = category, y = proportion)) + geom_bar(stat = "identity", fill = "steelblue") + theme_minimal()

We can see from this plot that YouTube vidoes that have more dislikes than likes have 4.8 times more probability that the video will disable comments.

Decision Tree

Get libaries needed for making decision tree

library(multcomp)
library(party)

Make another column that distinguishes whether the row has more dislikes than likes

dislike_decision <- youtube_trend %>%
                        mutate(dislike_more = ifelse(dislikes > likes, "yes", "no"))

Decision tree on how views, likes, comment count, and dislikes allows you to know whether the YouTube video has more dislikes than likes

tree <- dislike_decision %>%
    ctree(dislike_more == "yes" ~ views + likes + comment_count + dislikes, data = ., controls = ctree_control(maxdepth = 3))

plot(tree, type = "simple")

There are some interesting output here.
If a YouTube video has more than 3773 dislikes and have views less than 467531, than it has probability of 61.9% that the video will have more dislikes than likes.
This means we can predict with the accuracy of about 62% whether a video has more dislikes than likes just by using number of dislikes and number of views.

Decision tree on how views and comment count allows you to know whether the YouTube video has more dislikes than likes

tree2 <- dislike_decision %>%
    ctree(dislike_more == "yes" ~ views + comment_count, data = ., controls = ctree_control(maxdepth = 3))

plot(tree2, type = "simple")

We can see from this decision tree that it is difficult to predict or categorize a video whether it has more dislikes than likes with just number of views and comment_count

YouTube channels with a single video having most views

US Channels

us_channel_max <- us_youtube_trend %>%
                    group_by(channel_title) %>%
                    summarise(max = max(views)) %>%
                    filter(max > 10**8)
ggplot(us_channel_max, aes(x = reorder(channel_title, max), y = max)) + geom_bar(stat = "identity", fill = "steelblue") + theme_minimal() + coord_flip()

The video from channel “ChildishGambinoVEVO” had the most views out of a single video with staggering two hundred million views.

Canada Channels

ca_channel_max <- ca_youtube_trend %>%
                    group_by(channel_title) %>%
                    summarise(max = max(views)) %>%
                    filter(max > 5*10**7)
ggplot(ca_channel_max, aes(x = reorder(channel_title, max), y = max)) + geom_bar(stat = "identity", fill = "steelblue") + theme_minimal() + coord_flip()

The video from channel “YouTube Spotlight” had the most views out of a single video with staggering one hundred million views.

Top 10 Video Categories - Based on Views

US Channels

us_channel_categ <- 
  aggregate(views~category_id, data = us_youtube_trend, sum)%>%
  arrange(desc(views)) %>%
  head(10)

us_channel_categ

Canada Channels

ca_channel_categ <- 
  aggregate(views~category_id, data = ca_youtube_trend, sum)%>%
  arrange(desc(views)) %>%
  head(10)

ca_channel_categ

Top 5 Channels with highest reaction/response, based on the overall comments per view

US Channels

us_mutate <- 
  mutate(us_youtube_trend, new= ((comment_count/views)*1000))

us_mutate_categ <-
  us_mutate %>%
  group_by(category_id) %>%
  summarise(count= n(),total_probability = sum(new)) %>%
  mutate(average_probability= (count/total_probability)) %>%
  arrange(average_probability)

us_mutate_categ

CA Channels

ca_mutate <- 
  mutate(ca_youtube_trend, new= ((comment_count/views)*1000))

ca_mutate_categ <-
  ca_mutate %>%
  group_by(category_id) %>%
  summarise(count= n(),total_probability = sum(new)) %>%
  mutate(average_probability= (count/total_probability)) %>%
  arrange(average_probability)

ca_mutate_categ
LS0tDQp0aXRsZTogIlNUQVQgMTg0IC0gRmluYWwgUHJvamVjdCIgDQphdXRob3I6ICJEYW5pZWwgSnVuZywgWW9vamluIExpbSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIEZyb250IE1hdHRlcg0KYGBge3J9DQojIGNsZWFuIHVwIHdvcmtzcGFjZSBlbnZpcm9ubWVudA0Kcm0obGlzdCA9IGxzKCkpDQojIGFsbCBwYWNrYWdlcyB1c2VkIGZvciB0aGUgYXNzaWdubWVudA0KbGlicmFyeShtb3NhaWNEYXRhKQ0KbGlicmFyeShEYXRhQ29tcHV0aW5nKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpgYGANCg0KIyMgR3VpZGluZyBRdWVzdGlvbjogSXMgdGhlcmUgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gbnVtYmVyIG9mIGxpa2VzLCBkaXNsaWtlcyBhbmQgY29tbWVudHMgb24gWW91VHViZSBWaWRlb3M/IChDYW4gd2UgZmluZCBhbnkgcmVsYXRpb25zaGlwIGJldHdlZW4gbnVtYmVyIG9mIHZpZXdzLCBsaWtlcywgZGlzbGlrZXMgYW5kIGNvbW1lbnRzIGZyb20gWW91VHViZSB2aWRlb3M/KSANCigxKSBXZSB3YW50IHRvIGZpbmQgd2hldGhlciB0aGVyZSBpcyBhbnkgcmVsYXRpb25zaGlwIGJlYnR3ZWVuIG51bWJlciBvZiB2aWV3cywgbGlrZXMsIGRpc2xpa2VzIGFuZCBjb21tZW50cyBmcm9tIFlvdVR1YmUgdmlkZW9zPw0KKDIpIFdlIHdhbnQgdG8ga25vdyByZWNlbnQgdHJlbmQgb2YgWW91VHViZSB2aWV3ZXJzIGFuZCB0aGVpciBhY3Rpdml0eSB0aHJvdWdoIGRhdGEgb2Ygdmlld3MsIGxpa2VzLCBkaXNsaWtlcyBhbmQgY29tbWVudHMNCigyKSBUaGUgZGF0YSBoYXMgdGltZSBmcmFtZSBzdGFydGluZyBmcm9tIE5vdiAyMDE3IGVuZGluZyBpbiBKdW5lIDIwMTguDQoNCiMgSW1wb3J0IGRhdGENCmBgYHtyfQ0KZmlsZV9sb2NhdGlvbiA8LSBmaWxlLmNob29zZSgpDQoNCnVzX3lvdXR1YmVfdHJlbmQgPC0gcmVhZC5jc3YoZmlsZV9sb2NhdGlvbikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoY291bnRyeSA9ICJVUyIpDQoNCmZpbGVfbG9jYXRpb24gPC0gZmlsZS5jaG9vc2UoKQ0KDQpjYV95b3V0dWJlX3RyZW5kIDwtIHJlYWQuY3N2KGZpbGVfbG9jYXRpb24pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGNvdW50cnkgPSAiQ0EiKQ0KDQp5b3V0dWJlX3RyZW5kIDwtIHJiaW5kKHVzX3lvdXR1YmVfdHJlbmQsIGNhX3lvdXR1YmVfdHJlbmQpDQpgYGANCkdldHRpbmcgZGF0YSBmcm9tICJVU3ZpZGVvcy5jc3YiIGFuZCAiQ0F2aWRlb3MuY3N2IiB3aGljaCBpcyBnaXZlbiBieSBNaXRjaGVsbCBKIGluIEthZ2dsZS4gVGhlIGthZ2dsZSBsaW5rIGlzIGZvbGxvd2luZzogaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9kYXRhc25hZWsveW91dHViZS1uZXdcLiBUaGUgZGF0YSB3YXMgb3JpZ2luYWxseSBjb2xsZWN0ZWQgZm9yIGRhdGEgc2hhcmluZyBpbiBLYWdnbGUgd2VicGFnZSBhYm91dCAyIHllYXJzIGFnby4gRWFjaCBjYXNlIHJlcHJlc2VudCBvbmUgdHJlbmRpbmcgWW91VHViZSB2aWRlby4gRm9yIGV4YW1wbGUsIHRoZXJlIGlzIGEgcm93IGFib3V0IFlvdVR1YmUgdmlkZW8gcG9zdGVkIGJ5IEVtaW5lbS4gSXQgd2FzIHRyZWRpbmcgb24gTm92IDE0LCAyMDE3IGFuZCBoYWQgdmlld3Mgb2YgMTcxNTg1NzksIGxpa2VzIG9mIDc4NzQyNSwgZGlzbGlrZXMgb2YgNDM0MjAsIGFuZCBjb21tZW50cyBvZiAxMjU4ODIuIEluIG91ciBkYXRhc2V0LCB0aGVyZSBhcmUgNDA5MjYgcm93cyBvZiB0cmVuZGluZyBZb3VUdWJlIHZpZGVvcy4gSSBwbGFuIHRvIHVzZSB2YXJpYWJsZXMgInRyZW5kaW5nX2RhdGUiLCAidmlld3MiLCAibGlrZXMiLCAiZGlzbGlrZXMiLCAiY29tbWVudF9jb3VudCIsIGFuZCAiY29tbWVudF9kaXNhYmxlZCIuIFRoZSByZWdpb24gaXMgVVMgQU5EIENhbmFkYS4NCg0KIyBJbnNwZWN0IGRhdGENClRoZSBzaXggZXhhbXBsZSByb3dzIGFyZSBzaG93biBiZWxvdw0KYGBge3J9DQpoZWFkKHlvdXR1YmVfdHJlbmQpDQpgYGANCg0KVGhlc2UgYXJlIHRoZSBjb2x1bW4gbmFtZXMgb2YgInlvdXR1YmVfdHJlbmQiIGRhdGEgZnJhbWUNCmBgYHtyfQ0KbmFtZXMoeW91dHViZV90cmVuZCkNCmBgYA0KDQojIENsZWFuIGRhdGENCmBgYHtyfQ0KeW91dHViZV90cmVuZCA8LSB5b3V0dWJlX3RyZW5kICU+JQ0KICAgICAgICAgICAgICAgICAgICBmaWx0ZXIodmlkZW9fZXJyb3Jfb3JfcmVtb3ZlZCA9PSAiRmFsc2UiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRyZW5kaW5nX2RhdGUgPSB5ZG0odHJlbmRpbmdfZGF0ZSkpDQpgYGANClJlbW92ZSB2aWRlb3MgdGhhdCB3ZXJlIHJlbW92ZWQgb3Igd2FzIGNvbmZpcm1lZCB0byBiZSBhbiBlcnJvci4gVGhlc2UgdmlkZW9zIGFyZSBjbGFzc2lmaWVkIGFzICJUcnVlIiBmb3IgY29sdW1uICJ2aWRlb19lcnJvcl9vcl9yZW1vdmVkIg0KDQojIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIG51bWJlciBvZiB2aWV3cywgbGlrZXMsIGRpc2xpa2VzLCBhbmQgY29tbWVudHMgaW4gYSBzaW5nbGUgdmlkZW8NCmBgYHtyfQ0KZ2dwbG90KHlvdXR1YmVfdHJlbmQsIGFlcyh4ID0gdmlld3MsIHkgPSBsaWtlcywgY29sb3IgPSBjb3VudHJ5KSkgKyBnZW9tX3BvaW50KCkNCmBgYA0KV2UgY2FuIHNlZSBmcm9tIHRoZSBzY2F0dGVycGxvdCB0aGF0IHRoZXJlIHNlZW1zIHRvIGJlIGEgbG9nYXJpdGhtaWMgcmVsYXRpb25zaGlwIGJldHdlZW4gbnVtYmVyIG9mIHZpZXdzIGFuZCBudW1iZXIgb2YgbGlrZXMgaW4gYSBZb3VUdWJlIHZpZGVvLg0KDQpgYGB7cn0NCmdncGxvdCh5b3V0dWJlX3RyZW5kLCBhZXMoeCA9IHZpZXdzLCB5ID0gZGlzbGlrZXMsIGNvbG9yID0gY291bnRyeSkpICsgZ2VvbV9wb2ludCgpDQpgYGANCldlIGNhbiBzZWUgZnJvbSB0aGUgc2NhdHRlcnBsb3QgdGhhdCB0aGVyZSBzZWVtcyB0byBiZSBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBudW1iZXIgb2Ygdmlld3MgYW5kIG51bWJlciBvZiBkaXNsaWtlcyBpbiBZb3VUdWJlIHZpZGVvcy4gVGhpcyBtZWFucyB0aGF0IGl0IGlzIGV2aXRhYmxlIHRoYXQgdGhlcmUgc2hvdWxkIGJlIGluY3JlYXNlIGluIGRpc2xpa2VzIHdoZW4gbnVtYmVyIG9mIHZpZXdzIGluY3JlYXNlLiBXZSBjYW4gYXNsbyBzZWUgc29tZSB2aWRlb3MgaGF2ZSBoaWdlciByYXRlIG9mIGluY3JlYXNpbmcgZGlzbGlrZXMgZm9yIGNlcnRhaW4gYW1vdW50IG9mIHZpZXdzLg0KDQpgYGB7cn0NCmdncGxvdCh5b3V0dWJlX3RyZW5kLCBhZXMoeCA9IHZpZXdzLCB5ID0gY29tbWVudF9jb3VudCwgY29sb3IgPSBjb3VudHJ5KSkgKyBnZW9tX3BvaW50KCkNCmBgYA0KV2UgY2FuIHNlZSBmcm9tIHRoZSBzY2F0dGVycGxvdCB0aGF0IHRoZXJlIHNlZW1zIHRvIGJlIGEgbG9nYXJpdGhtaWMgKGJ1dCB2ZXJ5IGNsb3NlIHRvIGxpbmVhcikgcmVsYXRpb25zaGlwIGJldHdlZW4gbnVtYmVyIG9mIHZpZXdzIGFuZCBudW1iZXIgb2YgY29tbWVudHMgaW4gWW91VHViZSB2aWRlb3MuDQoNCmBgYHtyfQ0KZ2dwbG90KHlvdXR1YmVfdHJlbmQsIGFlcyh4ID0gbGlrZXMsIHkgPSBkaXNsaWtlcywgY29sb3IgPSBjb3VudHJ5KSkgKyBnZW9tX3BvaW50KCkNCmBgYA0KV2UgY2FuIHNlZSBmcm9tIHRoZSBzY2F0dGVycGxvdCB0aGF0IHRoZXJlIHNlZW1zIHRvIGJlIGEgdmVyeSBzdHJhaWdodCBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gbnVtYmVyIG9mIGxpa2VzIGFuZCBudW1iZXIgb2YgZGlzbGlrZXMgaW4gWW91VHViZSB2aWRlb3MuDQoNCmBgYHtyfQ0KZ2dwbG90KHlvdXR1YmVfdHJlbmQsIGFlcyh4ID0gbGlrZXMsIHkgPSBjb21tZW50X2NvdW50LCBjb2xvciA9IGNvdW50cnkpKSArIGdlb21fcG9pbnQoKQ0KYGBgDQpXZSBjYW4gc2VlIGZyb20gdGhlIHNjYXR0ZXJwbG90IHRoYXQgdGhlcmUgc2VlbXMgdG8gYmUgYSB2ZXJ5IHN0cmFpZ2h0IGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBudW1iZXIgb2YgbGlrZXMgYW5kIG51bWJlciBvZiBjaW1tZW50cyBpbiBZb3VUdWJlIHZpZGVvcy4NCg0KYGBge3J9DQpnZ3Bsb3QoeW91dHViZV90cmVuZCwgYWVzKHggPSBkaXNsaWtlcywgeSA9IGNvbW1lbnRfY291bnQsIGNvbG9yID0gY291bnRyeSkpICsgZ2VvbV9wb2ludCgpDQpgYGANCldlIGNhbiBzZWUgZnJvbSB0aGUgc2NhdHRlcnBsb3QgdGhhdCB0aGVyZSBzZWVtcyB0byBiZSBhIGxvZ2FyaXRobWljIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG51bWJlciBvZiBkaXNsaWtlcyBhbmQgbnVtYmVyIG9mIGNvbW1lbnQgaW4gWW91VHViZSB2aWRlb3MuDQoNCiMgSXMgdGhlcmUgYW55IHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRpc2FibGluZyBjb21tZW50IGFuZCBudW1iZXIgb2YgZGlzbGlrZXMgYSBZb3VUdWJlIHZpZGVvIHJlY2VpdmVkPw0KYGBge3J9DQpjb21fZGlzIDwtIHlvdXR1YmVfdHJlbmQgJT4lDQogICAgICAgICAgICAgIGZpbHRlcihjb21tZW50c19kaXNhYmxlZCA9PSAiVHJ1ZSIpDQoNCm1lYW4oY29tX2RpcyRkaXNsaWtlcykNCm1lYW4oY29tX2RpcyRsaWtlcykNCg0KY29tX25vbl9kaXMgPC0geW91dHViZV90cmVuZCAlPiUNCiAgICAgICAgICAgICAgICAgIGZpbHRlcihjb21tZW50c19kaXNhYmxlZCA9PSAiRmFsc2UiKQ0KDQptZWFuKGNvbV9ub25fZGlzJGRpc2xpa2VzKQ0KbWVhbihjb21fbm9uX2RpcyRsaWtlcykNCmBgYA0KVGhlIFlvdVR1YmUgdmlkZW9zIHdpdGggY29tbWVudCBkaXNhYmxlZCBoYXZlIGF2ZXJhZ2UgbnVtYmVyIG9mIDE5NjAuNjg1IGRpc2xpa2VzIGFuZCBhdmVyYWdlIG51bWJlciBvZiAxNzk0Ni4zMyBsaWtlcy4gWW91VHViZSB2aWRlb3Mgd2l0aCBjb21tZW50IG5vdCBkaXNhYmxlZCBoYXMgYXZlcmFnZSBudW1iZXIgb2YgMjg3NS4xMjcgZGlzbGlrZXMgYW5kIGF2ZXJhZ2UgbnVtYmVyIG9mIDU3NTMyLjQyIGxpa2VzLiBXZSBjYW4gc2VlIHRoYXQgdmlkZW9zIHRoYXQgaGF2ZSBjb21tZW50IGRpc2FibGVkIGdvdCBtdWNoIGxlc3MgbGlrZXMgYW5kIGRpc2xpa2VzIHRoYW4gdmlkb2VzIHRoYXQgaGF2ZSBjb21tZW50IGVuYWJsZWQuDQoNCiMgRm9yIFlvdVR1YmUgdmlkZW9zIHdpdGggbW9yZSBkaXNsaWtlcyB0aGFuIGxpa2VzLCBkbyB0aGVzZSB2aWRlb3MgaGF2ZSBoaWdlciBwcm9iYWJpbGl0eSBvZiBkaXNhYmxpbmcgY29tbWVudHMgdGhhbiB2aWRlb3MgdGhhdCBoYXZlIG1vcmUgbGlrZXMgdGhhbiBkaXNsaWtlcz8NCmBgYHtyfQ0KbW9yZV9kaXNsaWtlIDwtIHlvdXR1YmVfdHJlbmQgJT4lDQogICAgICAgICAgICAgICAgICBmaWx0ZXIoZGlzbGlrZXMgPiBsaWtlcykNCm1vcmVfbGlrZSA8LSB5b3V0dWJlX3RyZW5kICU+JQ0KICAgICAgICAgICAgICAgIGZpbHRlcihsaWtlcyA+IGRpc2xpa2VzKSAlPiUNCiAgICAgICAgICAgICAgICBzYW1wbGVfbig4NDEpDQpgYGANCkFzIHRoZXJlIGFyZSBvbmx5IDg0MSB2aWRlb3MgdGhhdCBoYXZlIG1vcmUgZGlzbGlrZXMgdGhhbiBsaWtlcywgd2Ugd2lsbCBhbHNvIHNhbXBsZSBvbmx5IDg0MSB2aWRlb3MgZnJvbSBsaXN0IG9mIHZpZGVvcyB0aGF0IGhhdmUgbW9yZSBsaWtlcyB0aGFuIGRpc2xpa2VzLg0KDQpgYGB7cn0NCmNvbV9kaXNfZGYgPC0gZGF0YS5mcmFtZShEYXRlPWFzLkRhdGUoY2hhcmFjdGVyKCkpLA0KICAgICAgICAgICAgICAgICBGaWxlPWNoYXJhY3RlcigpLCANCiAgICAgICAgICAgICAgICAgVXNlcj1jaGFyYWN0ZXIoKSwgDQogICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpIA0KDQpucm93KG1vcmVfZGlzbGlrZSkNCg0KY29tX2Rpc19kaXMgPC0gc3VtKG1vcmVfZGlzbGlrZSRjb21tZW50c19kaXNhYmxlZCA9PSAiVHJ1ZSIpDQpjb21fZGlzX2Rpcw0KDQpucm93KG1vcmVfbGlrZSkNCg0KY29tX2Rpc19ub24gPC0gc3VtKG1vcmVfbGlrZSRjb21tZW50c19kaXNhYmxlZCA9PSAiVHJ1ZSIpDQpjb21fZGlzX25vbg0KYGBgDQpGcm9tIDg0MSBZb3VUdWJlIHZpZGVvcyB0aGF0IGhhdmUgbW9yZSBkaXNsaWtlcyB0aGFuIGxpa2VzLCB0aGVyZSBhcmUgNTMgdmlkZW9zIHRoYXQgaGF2ZSB0aGVpciBjb21tZW50cyBkaXNhYmxlZC4gRnJvbSA4NDEgWW91VHViZSB2aWRlb3MgdGhhdCBoYXZlIG1vcmUgbGlrZXMgdGhhbiBkaXNsaWtlcywgdGhlcmUgYXJlIDEzIHZpZGVvcyB0aGF0IGhhdmUgdGhlaXIgY29tbWVudHMgZGlzYWJsZWQuICgqKlRoZSBudW1iZXIgb2YgdmlkZW9zIHRoYXQgaGF2ZSBtb3JlIGxpa2VzIHRoYW4gZGlzbGlrZXMgd2hpbGUgY29tbWVudHMgYXJlIGRpc2FibGVkIG1pZ2h0IHZhcnkgYXMgdGhlIHNhbXBsZSBtaWdodCBjaGFuZ2UgZnJvbSBzYW1wbGluZykNCg0KYGBge3J9DQpjb21fZGlzX2RmIDwtIHJiaW5kKGNvbV9kaXNfZGYsIGMoIm1vcmUgbGlrZSIsIGNvbV9kaXNfbm9uL25yb3cobW9yZV9saWtlKSksIGMoIm1vcmUgZGlzbGlrZSIsIGNvbV9kaXNfZGlzL25yb3cobW9yZV9kaXNsaWtlKSkpIA0KDQpjb2xuYW1lcyhjb21fZGlzX2RmKSA8LSBjKCJjYXRlZ29yeSIsICJwcm9wb3J0aW9uIikNCg0KY29tX2Rpc19kZg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGNvbV9kaXNfZGYsIGFlcyh4ID0gY2F0ZWdvcnksIHkgPSBwcm9wb3J0aW9uKSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJzdGVlbGJsdWUiKSArIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpXZSBjYW4gc2VlIGZyb20gdGhpcyBwbG90IHRoYXQgWW91VHViZSB2aWRvZXMgdGhhdCBoYXZlIG1vcmUgZGlzbGlrZXMgdGhhbiBsaWtlcyBoYXZlIDQuOCB0aW1lcyBtb3JlIHByb2JhYmlsaXR5IHRoYXQgdGhlIHZpZGVvIHdpbGwgZGlzYWJsZSBjb21tZW50cy4NCg0KIyMgRGVjaXNpb24gVHJlZQ0KR2V0IGxpYmFyaWVzIG5lZWRlZCBmb3IgbWFraW5nIGRlY2lzaW9uIHRyZWUNCmBgYHtyfQ0KbGlicmFyeShtdWx0Y29tcCkNCmxpYnJhcnkocGFydHkpDQpgYGANCg0KTWFrZSBhbm90aGVyIGNvbHVtbiB0aGF0IGRpc3Rpbmd1aXNoZXMgd2hldGhlciB0aGUgcm93IGhhcyBtb3JlIGRpc2xpa2VzIHRoYW4gbGlrZXMNCmBgYHtyfQ0KZGlzbGlrZV9kZWNpc2lvbiA8LSB5b3V0dWJlX3RyZW5kICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGRpc2xpa2VfbW9yZSA9IGlmZWxzZShkaXNsaWtlcyA+IGxpa2VzLCAieWVzIiwgIm5vIikpDQpgYGANCg0KIyMjIERlY2lzaW9uIHRyZWUgb24gaG93IHZpZXdzLCBsaWtlcywgY29tbWVudCBjb3VudCwgYW5kIGRpc2xpa2VzIGFsbG93cyB5b3UgdG8ga25vdyB3aGV0aGVyIHRoZSBZb3VUdWJlIHZpZGVvIGhhcyBtb3JlIGRpc2xpa2VzIHRoYW4gbGlrZXMNCmBgYHtyfQ0KdHJlZSA8LSBkaXNsaWtlX2RlY2lzaW9uICU+JQ0KICAgIGN0cmVlKGRpc2xpa2VfbW9yZSA9PSAieWVzIiB+IHZpZXdzICsgbGlrZXMgKyBjb21tZW50X2NvdW50ICsgZGlzbGlrZXMsIGRhdGEgPSAuLCBjb250cm9scyA9IGN0cmVlX2NvbnRyb2wobWF4ZGVwdGggPSAzKSkNCg0KcGxvdCh0cmVlLCB0eXBlID0gInNpbXBsZSIpDQpgYGANClRoZXJlIGFyZSBzb21lIGludGVyZXN0aW5nIG91dHB1dCBoZXJlLlwNCklmIGEgWW91VHViZSB2aWRlbyBoYXMgbW9yZSB0aGFuIDM3NzMgZGlzbGlrZXMgYW5kIGhhdmUgdmlld3MgbGVzcyB0aGFuIDQ2NzUzMSwgdGhhbiBpdCBoYXMgcHJvYmFiaWxpdHkgb2YgNjEuOSUgdGhhdCB0aGUgdmlkZW8gd2lsbCBoYXZlIG1vcmUgZGlzbGlrZXMgdGhhbiBsaWtlcy5cDQpUaGlzIG1lYW5zIHdlIGNhbiBwcmVkaWN0IHdpdGggdGhlIGFjY3VyYWN5IG9mIGFib3V0IDYyJSB3aGV0aGVyIGEgdmlkZW8gaGFzIG1vcmUgZGlzbGlrZXMgdGhhbiBsaWtlcyBqdXN0IGJ5IHVzaW5nIG51bWJlciBvZiBkaXNsaWtlcyBhbmQgbnVtYmVyIG9mIHZpZXdzLlwNCg0KIyMjIERlY2lzaW9uIHRyZWUgb24gaG93IHZpZXdzIGFuZCBjb21tZW50IGNvdW50IGFsbG93cyB5b3UgdG8ga25vdyB3aGV0aGVyIHRoZSBZb3VUdWJlIHZpZGVvIGhhcyBtb3JlIGRpc2xpa2VzIHRoYW4gbGlrZXMNCmBgYHtyfQ0KdHJlZTIgPC0gZGlzbGlrZV9kZWNpc2lvbiAlPiUNCiAgICBjdHJlZShkaXNsaWtlX21vcmUgPT0gInllcyIgfiB2aWV3cyArIGNvbW1lbnRfY291bnQsIGRhdGEgPSAuLCBjb250cm9scyA9IGN0cmVlX2NvbnRyb2wobWF4ZGVwdGggPSAzKSkNCg0KcGxvdCh0cmVlMiwgdHlwZSA9ICJzaW1wbGUiKQ0KYGBgDQpXZSBjYW4gc2VlIGZyb20gdGhpcyBkZWNpc2lvbiB0cmVlIHRoYXQgaXQgaXMgZGlmZmljdWx0IHRvIHByZWRpY3Qgb3IgY2F0ZWdvcml6ZSBhIHZpZGVvIHdoZXRoZXIgaXQgaGFzIG1vcmUgZGlzbGlrZXMgdGhhbiBsaWtlcyB3aXRoIGp1c3QgbnVtYmVyIG9mIHZpZXdzIGFuZCBjb21tZW50X2NvdW50IA0KDQojIE1vc3QgcG9wdWxhciBZb3VUdWJlIGNoYW5uZWwNCiMjIFVTIENoYW5uZWxzDQpgYGB7cn0NCnVzX2NoYW5uZWxfcG9wIDwtIHVzX3lvdXR1YmVfdHJlbmQgJT4lDQogICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGNoYW5uZWxfdGl0bGUpICU+JQ0KICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoY291bnQgPiAxNjApDQpgYGANCkluIG9yZGVyIHRvIG1ha2Ugb3VyIHBsb3QgbW9yZSByZWFkYWJsZSwgd2Ugd2lsbCBjb25zdHJhaW50IHRoZSBudW1iZXIgb2YgdmlkZW9zIHRoYXQgd2VyZSB0cmVuZGluZyB0byBiZSBncmVhdGVyIHRoYW4gMTYwLg0KDQpgYGB7cn0NCmdncGxvdCh1c19jaGFubmVsX3BvcCwgYWVzKHggPSByZW9yZGVyKGNoYW5uZWxfdGl0bGUsIGNvdW50KSwgeSA9IGNvdW50KSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJzdGVlbGJsdWUiKSArIHRoZW1lX21pbmltYWwoKSArIGNvb3JkX2ZsaXAoKQ0KYGBgDQpXZSBjYW4gc2VlIGZyb20gdGhpcyBwbG90IHRoYXQgdGhlIG1vc3QgcG9wdWxhciBZb3VUdWJlIGNoYW5uZWwgZnJvbSBOb3YgMjAxNyB0byBKdW5lIDIwMTggd2FzIEVTUE4uIEFsc28sIHNob3cgZnJvbSBKaW1teSBGYWxsb24sIFZveCwgRWxsZW4gc2hvdywgTmV0ZmxpeCB3ZXJlIGFsc28gdmVyeSBwb3B1bGFyLg0KDQojIyBDYW5hZGEgQ2hhbm5lbHMNCmBgYHtyfQ0KY2FfY2hhbm5lbF9wb3AgPC0gY2FfeW91dHViZV90cmVuZCAlPiUNCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2hhbm5lbF90aXRsZSkgJT4lDQogICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihjb3VudCA+IDE2MCkNCmBgYA0KSW4gb3JkZXIgdG8gbWFrZSBvdXIgcGxvdCBtb3JlIHJlYWRhYmxlLCB3ZSB3aWxsIGNvbnN0cmFpbnQgdGhlIG51bWJlciBvZiB2aWRlb3MgdGhhdCB3ZXJlIHRyZW5kaW5nIHRvIGJlIGdyZWF0ZXIgdGhhbiAxNjAuDQoNCmBgYHtyfQ0KZ2dwbG90KGNhX2NoYW5uZWxfcG9wLCBhZXMoeCA9IHJlb3JkZXIoY2hhbm5lbF90aXRsZSwgY291bnQpLCB5ID0gY291bnQpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInN0ZWVsYmx1ZSIpICsgdGhlbWVfbWluaW1hbCgpICsgY29vcmRfZmxpcCgpDQpgYGANCldlIGNhbiBzZWUgZnJvbSB0aGlzIHBsb3QgdGhhdCB0aGUgbW9zdCBwb3B1bGFyIFlvdVR1YmUgY2hhbm5lbCBmcm9tIE5vdiAyMDE3IHRvIEp1bmUgMjAxOCB3YXMgU0VUIEluZGlhLiBBbHNvLCB2aWRlb3MgZnJvbSBNU05CQywgRkJFLCAiVGhlIFlvdW5nIFR1cmtzIiB3ZXJlIGFsc28gdmVyeSBwb3B1bGFyLg0KDQojIFlvdVR1YmUgY2hhbm5lbHMgd2l0aCBhIHNpbmdsZSB2aWRlbyBoYXZpbmcgbW9zdCB2aWV3cw0KIyMgVVMgQ2hhbm5lbHMNCmBgYHtyfQ0KdXNfY2hhbm5lbF9tYXggPC0gdXNfeW91dHViZV90cmVuZCAlPiUNCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY2hhbm5lbF90aXRsZSkgJT4lDQogICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShtYXggPSBtYXgodmlld3MpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKG1heCA+IDEwKio4KQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KHVzX2NoYW5uZWxfbWF4LCBhZXMoeCA9IHJlb3JkZXIoY2hhbm5lbF90aXRsZSwgbWF4KSwgeSA9IG1heCkpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic3RlZWxibHVlIikgKyB0aGVtZV9taW5pbWFsKCkgKyBjb29yZF9mbGlwKCkNCmBgYA0KVGhlIHZpZGVvIGZyb20gY2hhbm5lbCAiQ2hpbGRpc2hHYW1iaW5vVkVWTyIgaGFkIHRoZSBtb3N0IHZpZXdzIG91dCBvZiBhIHNpbmdsZSB2aWRlbyB3aXRoIHN0YWdnZXJpbmcgdHdvIGh1bmRyZWQgbWlsbGlvbiB2aWV3cy4NCg0KIyMgQ2FuYWRhIENoYW5uZWxzDQpgYGB7cn0NCmNhX2NoYW5uZWxfbWF4IDwtIGNhX3lvdXR1YmVfdHJlbmQgJT4lDQogICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGNoYW5uZWxfdGl0bGUpICU+JQ0KICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobWF4ID0gbWF4KHZpZXdzKSkgJT4lDQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihtYXggPiA1KjEwKio3KQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGNhX2NoYW5uZWxfbWF4LCBhZXMoeCA9IHJlb3JkZXIoY2hhbm5lbF90aXRsZSwgbWF4KSwgeSA9IG1heCkpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic3RlZWxibHVlIikgKyB0aGVtZV9taW5pbWFsKCkgKyBjb29yZF9mbGlwKCkNCmBgYA0KVGhlIHZpZGVvIGZyb20gY2hhbm5lbCAiWW91VHViZSBTcG90bGlnaHQiIGhhZCB0aGUgbW9zdCB2aWV3cyBvdXQgb2YgYSBzaW5nbGUgdmlkZW8gd2l0aCBzdGFnZ2VyaW5nIG9uZSBodW5kcmVkIG1pbGxpb24gdmlld3MuDQoNCiMgVG90YWwgdmlld3MgYnkgdHJlbmRpbmcgZGF0ZQ0KYGBge3J9DQp0b3RhbF92aWV3c19ieV9kYXRlIDwtIHlvdXR1YmVfdHJlbmQgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KHRyZW5kaW5nX2RhdGUpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UodG90YWxfdmlld3MgPSBzdW0odmlld3MpKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KHRvdGFsX3ZpZXdzX2J5X2RhdGUsIGFlcyh4ID0gdHJlbmRpbmdfZGF0ZSwgeSA9IHRvdGFsX3ZpZXdzKSkgKyBnZW9tX2xpbmUoYWVzKHggPSB0cmVuZGluZ19kYXRlLCB5ID0gdG90YWxfdmlld3MsIGdyb3VwID0gMSkpICsgdGhlbWVfbWluaW1hbCgpDQpgYGANCldlIGNhbiBzZWUgZnJvbSB0aGlzIHBsb3QgdGhhdCB0aGUgdG90YWwgbnVtYmVyIG9mIHZpZXdzIGZyb20gdHJlbmRpbmcgdmlkZW9zIGhhdmUgaW5jcmVhc2VzIHF1aXRlIGEgYml0IHNpbmNlIEFwcmlsLg0KDQojIFRvdGFsIGxpa2VzIGFuZCBkaXNsaWtlcyBieSB0cmVuZGluZyBkYXRlIChZb3VUdWJlIHNlbnRpbWVudCkNCmBgYHtyfQ0KbGlrZXNfZGlzbGlrZXMgPC0geW91dHViZV90cmVuZCAlPiUNCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkodHJlbmRpbmdfZGF0ZSkgJT4lDQogICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSh0b3RhbF9saWtlcyA9IHN1bShsaWtlcyksIHRvdGFsX2Rpc2xpa2VzID0gc3VtKGRpc2xpa2VzKSwgdG90YWxfY29tbWVudHMgPSBzdW0oY29tbWVudF9jb3VudCkpDQoNCmxpa2VzX2Rpc2xpa2VzIDwtIGxpa2VzX2Rpc2xpa2VzICU+JQ0KICAgICAgICAgICAgICAgICAgICBwaXZvdF9sb25nZXIoY29scyA9IGModG90YWxfbGlrZXMsIHRvdGFsX2Rpc2xpa2VzLCB0b3RhbF9jb21tZW50cyksIG5hbWVzX3RvID0gInNlbnRpbWVudCIsIHZhbHVlc190byA9ICJjb3VudCIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QobGlrZXNfZGlzbGlrZXMsIGFlcyh4ID0gdHJlbmRpbmdfZGF0ZSwgeSA9IGNvdW50LCBncm91cCA9IHNlbnRpbWVudCwgY29sb3VyID0gc2VudGltZW50KSkgKyBnZW9tX2xpbmUoc2l6ZSA9IDEpICsgdGhlbWVfbWluaW1hbCgpDQpgYGANClRvdGFsIG51bWJlciBvZiBsaWtlcyBoYXZlIGFsc28gaW5jcmVhc2UgZHJhbWF0aWNhbGx5IHNpbmNlIEFwcmlsLiBJdCB3YXMgaW50ZXJlc3RpbmcgdGhhdCB0aGUgaW5jcmVhc2Ugb2YgZGlzbGlrZXMgaGF2ZSBub3QgYmVlbiBpbmNyZWFzZWQgYXMgbXVjaCBhcyBsaWtlcy4gV2UgY291bGQgc2VlIHRoYXQgdHJlbmRpbmcgdmlkZW9zIGhhdmUgZ2VuZXJhdGVkIHRvbnMgb2YgbGlrZXMgd2hpbGUgbm90IG11Y2ggY2hhbmdlIGluIGRpc2xpa2VzLg0KDQpgYGB7cn0NCnByb3BvcnRpb25hbF9saWtlcyA8LSB5b3V0dWJlX3RyZW5kICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkodHJlbmRpbmdfZGF0ZSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UodG90YWxfbGlrZXMgPSBzdW0obGlrZXMpLCB0b3RhbF9kaXNsaWtlcyA9IHN1bShkaXNsaWtlcyksIHRvdGFsX2NvbW1lbnRzID0gc3VtKGNvbW1lbnRfY291bnQpKQ0KDQpnZ3Bsb3QocHJvcG9ydGlvbmFsX2xpa2VzLCBhZXMoeCA9IHRyZW5kaW5nX2RhdGUsIHkgPSB0b3RhbF9saWtlcy90b3RhbF9kaXNsaWtlcykpICsgZ2VvbV9saW5lKHNpemUgPSAxKSArIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpIb3dldmVyIGlmIHdlIHNlZSB0aGlzIHBsb3QgLHdoaWNoIHBsb3RzIHRoZSBwcm9wb3J0aW9uIG9mIGxpa2VzIGFuZCBkaXNsaWtlcyBmb3IgZWFjaCBkYXksIHdlIGNhbiBzZWUgdGhhdCB0aGVyZSBoYXNuJ3QgYmVlbiBhIGxvdCBvZiBjaGFuZ2Ugb2YgcHJvcG9ydGlvbiBkdXJpbmcgdGhlIGRhdGVzIHdoZW4gZGF0YSB3YXMgcmVjb3JkZWQuDQoNCiMgVG9wIDEwIFZpZGVvIENhdGVnb3JpZXMgLSBCYXNlZCBvbiBWaWV3cw0KIyMgVVMgQ2hhbm5lbHMNCmBgYHtyfQ0KdXNfY2hhbm5lbF9jYXRlZyA8LSANCiAgYWdncmVnYXRlKHZpZXdzfmNhdGVnb3J5X2lkLCBkYXRhID0gdXNfeW91dHViZV90cmVuZCwgc3VtKSU+JQ0KICBhcnJhbmdlKGRlc2Modmlld3MpKSAlPiUNCiAgaGVhZCgxMCkNCg0KdXNfY2hhbm5lbF9jYXRlZw0KYGBgDQoNCiMjIENhbmFkYSBDaGFubmVscw0KDQpgYGB7cn0NCmNhX2NoYW5uZWxfY2F0ZWcgPC0gDQogIGFnZ3JlZ2F0ZSh2aWV3c35jYXRlZ29yeV9pZCwgZGF0YSA9IGNhX3lvdXR1YmVfdHJlbmQsIHN1bSklPiUNCiAgYXJyYW5nZShkZXNjKHZpZXdzKSkgJT4lDQogIGhlYWQoMTApDQoNCmNhX2NoYW5uZWxfY2F0ZWcNCmBgYA0KDQoNCg0KIyBUb3AgNSBDaGFubmVscyB3aXRoIGhpZ2hlc3QgcmVhY3Rpb24vcmVzcG9uc2UsIGJhc2VkIG9uIHRoZSBvdmVyYWxsIGNvbW1lbnRzIHBlciB2aWV3DQojIyBVUyBDaGFubmVscw0KDQpgYGB7cn0NCnVzX211dGF0ZSA8LSANCiAgbXV0YXRlKHVzX3lvdXR1YmVfdHJlbmQsIG5ldz0gKChjb21tZW50X2NvdW50L3ZpZXdzKSoxMDAwKSkNCg0KdXNfbXV0YXRlX2NhdGVnIDwtDQogIHVzX211dGF0ZSAlPiUNCiAgZ3JvdXBfYnkoY2F0ZWdvcnlfaWQpICU+JQ0KICBzdW1tYXJpc2UoY291bnQ9IG4oKSx0b3RhbF9wcm9iYWJpbGl0eSA9IHN1bShuZXcpKSAlPiUNCiAgbXV0YXRlKGF2ZXJhZ2VfcHJvYmFiaWxpdHk9IChjb3VudC90b3RhbF9wcm9iYWJpbGl0eSkpICU+JQ0KICBhcnJhbmdlKGF2ZXJhZ2VfcHJvYmFiaWxpdHkpDQoNCnVzX211dGF0ZV9jYXRlZw0KDQoNCmBgYA0KDQojIyBDQSBDaGFubmVscw0KDQpgYGB7cn0NCmNhX211dGF0ZSA8LSANCiAgbXV0YXRlKGNhX3lvdXR1YmVfdHJlbmQsIG5ldz0gKChjb21tZW50X2NvdW50L3ZpZXdzKSoxMDAwKSkNCg0KY2FfbXV0YXRlX2NhdGVnIDwtDQogIGNhX211dGF0ZSAlPiUNCiAgZ3JvdXBfYnkoY2F0ZWdvcnlfaWQpICU+JQ0KICBzdW1tYXJpc2UoY291bnQ9IG4oKSx0b3RhbF9wcm9iYWJpbGl0eSA9IHN1bShuZXcpKSAlPiUNCiAgbXV0YXRlKGF2ZXJhZ2VfcHJvYmFiaWxpdHk9IChjb3VudC90b3RhbF9wcm9iYWJpbGl0eSkpICU+JQ0KICBhcnJhbmdlKGF2ZXJhZ2VfcHJvYmFiaWxpdHkpDQoNCmNhX211dGF0ZV9jYXRlZw0KYGBgDQoNCg0KDQoNCg0K